Skip to content

Elasticsearch Query DSL 查詢語法筆記

TLDR

  • Query DSL 優勢:相比 Query String,DSL 支援 Nested 巢狀查詢、地理空間查詢、自訂評分(Function Score)及更複雜的布林邏輯,且結構清晰、錯誤訊息明確。
  • Match Query:全文檢索的核心,operator 可控制邏輯(OR/AND),minimum_should_match 支援靈活的數量與百分比規則,fuzziness 支援模糊比對。
  • Multi Match Query:提供 best_fields(預設,取最高分)、most_fields(加總分數)、cross_fields(跨欄位視為整體)等模式,適用於多欄位搜尋。
  • Combined Fields Query:以詞彙為中心,將多個 text 欄位視為單一組合欄位,適合處理關鍵字分散在標題、摘要與內文的情況。
  • Range Query:處理數值與日期範圍,日期查詢建議使用 format 明確定義格式,並優先使用字串格式以避免數值被解析為毫秒時間戳記。
  • Nested Query:當欄位為 nested 型別時必須使用,能保留陣列元素內部欄位的關聯性,避免 object 型別扁平化導致的查詢錯誤。
  • 效能警示wildcardregexp 查詢效能較差,應避免使用前導萬用字元,並限制 max_determinized_states 以防止資源耗盡。

Query DSL vs Query String

在正式環境中,Query DSL 是更推薦的選擇。相比 Query String,它具備以下優點:

  • 功能完整性:Nested 查詢、地理空間查詢、自訂評分(function_score)及複雜布林邏輯組合,皆僅能透過 Query DSL 實作。
  • 結構清晰:JSON 結構明確定義了查詢型別與參數,易於維護與除錯,且錯誤訊息能精確指出問題欄位。

常用 Query DSL 語法

1. Match Query - 全文檢索查詢

用於全文檢索,會進行分詞與相關性評分。

  • operator 參數:控制多個 token 的邏輯關係。OR 為預設值;AND 要求文件必須包含所有詞。
  • minimum_should_match:僅在 operator = "OR" 時有效。支援正整數(絕對數量)、負整數(允許遺漏數量)、百分比(無條件捨去)及條件組合(如 3<90%)。
  • fuzziness:僅適用於 text 欄位。建議設為 AUTO,讓 Elasticsearch 自動根據詞長決定編輯距離。
  • lenient:預設為 false。設為 true 可在型別不符時忽略該欄位,避免查詢拋出錯誤。
  • zero_terms_query:當分詞後無 token 時,none(預設)不回傳結果,all 則回傳所有文件。

2. Multi Match Query - 多欄位查詢

在多個欄位中搜尋相同關鍵字。

  • best_fields(預設):取最高分欄位,適合尋找「單一欄位最符合」的情況。
  • most_fields:加總所有欄位分數,適合「多個相似欄位」的場景。
  • cross_fields:將多個欄位視為一個大欄位,適合姓名、地址等跨欄位符合的查詢。
  • phrase / phrase_prefix / bool_prefix:針對片語與前綴的特殊查詢類型,適用於自動完成或精確片語搜尋。

3. Combined Fields Query - 跨欄位詞彙查詢

採用以詞彙為中心的方式,將多個 text 欄位視為單一組合欄位。

  • 限制:所有欄位必須是 text 型別且使用相同的 search_analyzer
  • 優勢:處理關鍵字分散在多個欄位(如標題、摘要、內文)時表現優異。

4. Match Phrase Query - 片語查詢

要求詞彙必須按順序出現。

  • slop 參數:允許詞彙之間的最大間隔數,預設為 0(必須完全相鄰)。

5. Term 與 Terms Query - 精確符合

  • Term:用於精確值查詢,不進行分詞。對 text 欄位使用時,會比對分詞後的詞項(term)。
  • Terms:類似 SQL 的 IN 查詢。支援 Terms Lookup,可從現有文件中取得欄位值作為搜尋條件。

6. Range Query - 範圍查詢

用於數值與日期範圍。

  • 日期處理:建議明確指定 format。若混用數值與字串,數值會被解釋為毫秒時間戳記,導致解析錯誤,建議統一使用字串格式。
  • Date Math:支援 now+1h-1d 等運算,並可透過 || 搭配捨入運算(如 /d/M)。

7. Exists Query - 欄位存在查詢

查詢某欄位是否存在(非 null)。

  • 反向查詢:使用 bool 查詢搭配 must_notexists
  • 注意事項:若欄位設定 index: falsedoc_values: false 或超過 ignore_above 限制,該欄位將無法被 exists 查詢偵測到。

8. Prefix, Wildcard 與 Regexp Query

  • Prefix:查詢以特定字串開頭的文件。
  • Wildcard:使用 *? 進行模糊查詢。避免使用前導萬用字元(如 *term),以免觸發全表掃描。
  • Regexp:支援正規表達式。效能最差,應盡量避免。Lucene 引擎不支援 ^$ 錨點,正規表達式預設匹配整個字串。

9. Fuzzy Query - 模糊查詢

容錯查詢,允許拼字錯誤。

  • 建議:對於 text 欄位,優先使用 match 查詢搭配 fuzziness 參數,而非直接使用 fuzzy 查詢,以確保查詢詞能經過分析器處理。

10. Nested Query - 巢狀物件查詢

用於查詢 nested 型別欄位,能保留陣列元素內部的關聯性。

  • 問題情境:若使用 object 型別,陣列會被扁平化,導致查詢時失去元素間的關聯(例如「John 給 5 分」會被誤判為「John 給 3 分」)。
  • 解決方案:將欄位定義為 nested 型別,並使用 nested 查詢,確保條件在「同一個子文件內」匹配。
  • inner_hits:可透過此參數取得具體符合條件的巢狀物件,而非僅回傳主文件。

異動歷程

    • 初版文件建立。